﻿// Inner Fire 游戏引擎库
// 场景分装 - 天空盒
//
// Copyright (c) 2023 by 尔西大帝. All rights reserved.
//
// 这个类分装各种场景的构建（都在一个文件里面太大了）
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-11-28

#include <dx_graphics.h>

namespace ifire {

void DxGraphics::Cube_Update() {
  UpdateObjectCBs_V2();
  UpdateMaterialBuffer_V2();
  UpdateMainPassCB_V2();
}
void DxGraphics::Cube_InitPipeline() {
  Cube_LoadTextures();
  Cube_BuildRootSignature();
  Cube_BuildDescriptorHeaps();
  Cube_BuildShadersAndInputLayout();
  Altar_BuildShapeGeometry();
  Altar_BuildSkullGeometry();
  Cube_BuildMaterials();
  Cube_BuildRenderItems();
  BuildFrameResources_V2();
  Cube_BuildPSOs();
}
void DxGraphics::Cube_Draw() {
  auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;

  // Reuse the memory associated with command recording.
  // We can only reset when the associated command lists have finished execution
  // on the GPU.
  ThrowIfFailed(cmdListAlloc->Reset());

  // A command list can be reset after it has been added to the command queue
  // via ExecuteCommandList. Reusing the command list reuses memory.
  ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));

  mCommandList->RSSetViewports(1, &mScreenViewport);
  mCommandList->RSSetScissorRects(1, &mScissorRect);

  // Indicate a state transition on the resource usage.
  auto to_render = CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
      D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
  mCommandList->ResourceBarrier(1, &to_render);

  // Clear the back buffer and depth buffer.
  auto dsv = DepthStencilView();
  auto back = CurrentBackBufferView();
  mCommandList->ClearRenderTargetView(back, Colors::LightSteelBlue, 0, nullptr);
  mCommandList->ClearDepthStencilView(dsv,
      D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);

  // Specify the buffers we are going to render to.
  mCommandList->OMSetRenderTargets(1, &back, true, &dsv);

  ID3D12DescriptorHeap* descriptorHeaps[] = {mSrvDescriptorHeap.Get()};
  mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);

  mCommandList->SetGraphicsRootSignature(mRootSignature.Get());

  auto passCB = mCurrFrameResource->PassCB->Resource();
  mCommandList->SetGraphicsRootConstantBufferView(
      1, passCB->GetGPUVirtualAddress());

  // Bind all the materials used in this scene.  For structured buffers, we can
  // bypass the heap and set as a root descriptor.
  auto matBuffer = mCurrFrameResource->MaterialBuffer->Resource();
  mCommandList->SetGraphicsRootShaderResourceView(
      2, matBuffer->GetGPUVirtualAddress());

  // Bind the sky cube map.  For our demos, we just use one "world" cube map
  // representing the environment from far away, so all objects will use the
  // same cube map and we only need to set it once per-frame. If we wanted to
  // use "local" cube maps, we would have to change them per-object, or
  // dynamically index into an array of cube maps.

  CD3DX12_GPU_DESCRIPTOR_HANDLE skyTexDescriptor(
      mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
  skyTexDescriptor.Offset(mSkyTexHeapIndex, mCbvSrvDescriptorSize);
  mCommandList->SetGraphicsRootDescriptorTable(3, skyTexDescriptor);

  // Bind all the textures used in this scene.  Observe
  // that we only have to specify the first descriptor in the table.
  // The root signature knows how many descriptors are expected in the table.
  mCommandList->SetGraphicsRootDescriptorTable(
      4, mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());

  DrawRenderItems_V2(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Opaque]);

  mCommandList->SetPipelineState(mPSOs["sky"].Get());
  DrawRenderItems_V2(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Sky]);

  // Indicate a state transition on the resource usage.
  auto to_present = CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
      D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
  mCommandList->ResourceBarrier(1, &to_present);

  // Done recording commands.
  ThrowIfFailed(mCommandList->Close());

  // Add the command list to the queue for execution.
  ID3D12CommandList* cmdsLists[] = {mCommandList.Get()};
  mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);

  // Swap the back and front buffers
  ThrowIfFailed(mSwapChain->Present(0, 0));
  mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;

  // Advance the fence value to mark commands up to this fence point.
  mCurrFrameResource->Fence = ++mCurrentFence;

  // Add an instruction to the command queue to set a new fence point.
  // Because we are on the GPU timeline, the new fence point won't be
  // set until the GPU finishes processing all the commands prior to this
  // Signal().
  mCommandQueue->Signal(mFence.Get(), mCurrentFence);
}
void DxGraphics::Cube_LoadTextures() {
  std::vector<std::string> texNames = {
      "bricksDiffuseMap", "tileDiffuseMap", "defaultDiffuseMap", "skyCubeMap"};

  std::vector<std::string> texFilenames = {//
      "Textures/bricks2.dds",              //
      "Textures/tile.dds",                 //
      "Textures/white1x1.dds",             //
      "Textures/grasscube1024.dds"};

  for (int i = 0; i < (int)texNames.size(); ++i) {
    auto texMap = std::make_unique<Texture>();
    texMap->Name = texNames[i];
    texMap->Filename = texFilenames[i];
    ThrowIfFailed(LoadDDS(
        texMap->Filename.c_str(), texMap->Resource, texMap->UploadHeap));

    mTextures[texMap->Name] = std::move(texMap);
  }
}
void DxGraphics::Cube_BuildRootSignature() {
  CD3DX12_DESCRIPTOR_RANGE texTable0;
  texTable0.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0);

  CD3DX12_DESCRIPTOR_RANGE texTable1;
  texTable1.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 5, 1, 0);

  // Root parameter can be a table, root descriptor or root constants.
  CD3DX12_ROOT_PARAMETER slotRootParameter[5];

  // Perfomance TIP: Order from most frequent to least frequent.
  slotRootParameter[0].InitAsConstantBufferView(0);
  slotRootParameter[1].InitAsConstantBufferView(1);
  slotRootParameter[2].InitAsShaderResourceView(0, 1);
  slotRootParameter[3].InitAsDescriptorTable(
      1, &texTable0, D3D12_SHADER_VISIBILITY_PIXEL);
  slotRootParameter[4].InitAsDescriptorTable(
      1, &texTable1, D3D12_SHADER_VISIBILITY_PIXEL);

  auto staticSamplers = GetStaticSamplers();

  // A root signature is an array of root parameters.
  CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(5, slotRootParameter,
      (UINT)staticSamplers.size(), staticSamplers.data(),
      D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

  // create a root signature with a single slot which points to a descriptor
  // range consisting of a single constant buffer
  ComPtr<ID3DBlob> serializedRootSig = nullptr;
  ComPtr<ID3DBlob> errorBlob = nullptr;
  HRESULT hr =
      D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
          serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());

  if (errorBlob != nullptr) {
    ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  }
  ThrowIfFailed(hr);

  ThrowIfFailed(md3dDevice->CreateRootSignature(0,
      serializedRootSig->GetBufferPointer(), serializedRootSig->GetBufferSize(),
      IID_PPV_ARGS(mRootSignature.GetAddressOf())));
}
void DxGraphics::Cube_BuildDescriptorHeaps() {
  //
  // Create the SRV heap.
  //
  D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
  srvHeapDesc.NumDescriptors = 5;
  srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  ThrowIfFailed(md3dDevice->CreateDescriptorHeap(
      &srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));

  //
  // Fill out the heap with actual descriptors.
  //
  CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(
      mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());

  auto bricksTex = mTextures["bricksDiffuseMap"]->Resource;
  auto tileTex = mTextures["tileDiffuseMap"]->Resource;
  auto whiteTex = mTextures["defaultDiffuseMap"]->Resource;
  auto skyTex = mTextures["skyCubeMap"]->Resource;

  D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  srvDesc.Format = bricksTex->GetDesc().Format;
  srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  srvDesc.Texture2D.MostDetailedMip = 0;
  srvDesc.Texture2D.MipLevels = bricksTex->GetDesc().MipLevels;
  srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
  md3dDevice->CreateShaderResourceView(bricksTex.Get(), &srvDesc, hDescriptor);

  // next descriptor
  hDescriptor.Offset(1, mCbvSrvDescriptorSize);

  srvDesc.Format = tileTex->GetDesc().Format;
  srvDesc.Texture2D.MipLevels = tileTex->GetDesc().MipLevels;
  md3dDevice->CreateShaderResourceView(tileTex.Get(), &srvDesc, hDescriptor);

  // next descriptor
  hDescriptor.Offset(1, mCbvSrvDescriptorSize);

  srvDesc.Format = whiteTex->GetDesc().Format;
  srvDesc.Texture2D.MipLevels = whiteTex->GetDesc().MipLevels;
  md3dDevice->CreateShaderResourceView(whiteTex.Get(), &srvDesc, hDescriptor);

  // next descriptor
  hDescriptor.Offset(1, mCbvSrvDescriptorSize);

  srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
  srvDesc.TextureCube.MostDetailedMip = 0;
  srvDesc.TextureCube.MipLevels = skyTex->GetDesc().MipLevels;
  srvDesc.TextureCube.ResourceMinLODClamp = 0.0f;
  srvDesc.Format = skyTex->GetDesc().Format;
  md3dDevice->CreateShaderResourceView(skyTex.Get(), &srvDesc, hDescriptor);

  mSkyTexHeapIndex = 3;
}
void DxGraphics::Cube_BuildShadersAndInputLayout() {
  const D3D_SHADER_MACRO alphaTestDefines[] = {"ALPHA_TEST", "1", NULL, NULL};

  mShaders["standardVS"] = d3dUtil::CompileShader(
      "Shaders\\Default_Cube.hlsl", nullptr, "VS", "vs_5_1");
  mShaders["opaquePS"] = d3dUtil::CompileShader(
      "Shaders\\Default_Cube.hlsl", nullptr, "PS", "ps_5_1");

  mShaders["skyVS"] =
      d3dUtil::CompileShader("Shaders\\Sky.hlsl", nullptr, "VS", "vs_5_1");
  mShaders["skyPS"] =
      d3dUtil::CompileShader("Shaders\\Sky.hlsl", nullptr, "PS", "ps_5_1");

  mInputLayout = {
      {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
  };
}
void DxGraphics::Cube_BuildMaterials() {
  auto bricks0 = std::make_unique<Material>();
  bricks0->Name = "bricks0";
  bricks0->MatCBIndex = 0;
  bricks0->DiffuseSrvHeapIndex = 0;
  bricks0->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  bricks0->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
  bricks0->Roughness = 0.3f;

  auto tile0 = std::make_unique<Material>();
  tile0->Name = "tile0";
  tile0->MatCBIndex = 1;
  tile0->DiffuseSrvHeapIndex = 1;
  tile0->DiffuseAlbedo = XMFLOAT4(0.9f, 0.9f, 0.9f, 1.0f);
  tile0->FresnelR0 = XMFLOAT3(0.2f, 0.2f, 0.2f);
  tile0->Roughness = 0.1f;

  auto mirror0 = std::make_unique<Material>();
  mirror0->Name = "mirror0";
  mirror0->MatCBIndex = 2;
  mirror0->DiffuseSrvHeapIndex = 2;
  mirror0->DiffuseAlbedo = XMFLOAT4(0.0f, 0.0f, 0.1f, 1.0f);
  mirror0->FresnelR0 = XMFLOAT3(0.98f, 0.97f, 0.95f);
  mirror0->Roughness = 0.1f;

  auto skullMat = std::make_unique<Material>();
  skullMat->Name = "skullMat";
  skullMat->MatCBIndex = 3;
  skullMat->DiffuseSrvHeapIndex = 2;
  skullMat->DiffuseAlbedo = XMFLOAT4(0.8f, 0.8f, 0.8f, 1.0f);
  skullMat->FresnelR0 = XMFLOAT3(0.2f, 0.2f, 0.2f);
  skullMat->Roughness = 0.2f;

  auto sky = std::make_unique<Material>();
  sky->Name = "sky";
  sky->MatCBIndex = 4;
  sky->DiffuseSrvHeapIndex = 3;
  sky->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  sky->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
  sky->Roughness = 1.0f;

  mMaterials["bricks0"] = std::move(bricks0);
  mMaterials["tile0"] = std::move(tile0);
  mMaterials["mirror0"] = std::move(mirror0);
  mMaterials["skullMat"] = std::move(skullMat);
  mMaterials["sky"] = std::move(sky);
}
void DxGraphics::Cube_BuildRenderItems() {
  auto skyRitem = std::make_unique<RenderItem>();
  XMStoreFloat4x4(&skyRitem->World, XMMatrixScaling(5000.0f, 5000.0f, 5000.0f));
  skyRitem->TexTransform = MathHelper::Identity4x4();
  skyRitem->ObjCBIndex = 0;
  skyRitem->Mat = mMaterials["sky"].get();
  skyRitem->Geo = mGeometries["shapeGeo"].get();
  skyRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  skyRitem->IndexCount = skyRitem->Geo->DrawArgs["sphere"].IndexCount;
  skyRitem->StartIndexLocation =
      skyRitem->Geo->DrawArgs["sphere"].StartIndexLocation;
  skyRitem->BaseVertexLocation =
      skyRitem->Geo->DrawArgs["sphere"].BaseVertexLocation;

  mRitemLayer[(int)RenderLayer::Sky].push_back(skyRitem.get());
  mAllRitems.push_back(std::move(skyRitem));

  auto boxRitem = std::make_unique<RenderItem>();
  XMStoreFloat4x4(&boxRitem->World, XMMatrixScaling(2.0f, 1.0f, 2.0f) *
                                        XMMatrixTranslation(0.0f, 0.5f, 0.0f));
  XMStoreFloat4x4(&boxRitem->TexTransform, XMMatrixScaling(1.0f, 1.0f, 1.0f));
  boxRitem->ObjCBIndex = 1;
  boxRitem->Mat = mMaterials["bricks0"].get();
  boxRitem->Geo = mGeometries["shapeGeo"].get();
  boxRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  boxRitem->IndexCount = boxRitem->Geo->DrawArgs["box"].IndexCount;
  boxRitem->StartIndexLocation =
      boxRitem->Geo->DrawArgs["box"].StartIndexLocation;
  boxRitem->BaseVertexLocation =
      boxRitem->Geo->DrawArgs["box"].BaseVertexLocation;

  mRitemLayer[(int)RenderLayer::Opaque].push_back(boxRitem.get());
  mAllRitems.push_back(std::move(boxRitem));

  auto skullRitem = std::make_unique<RenderItem>();
  XMStoreFloat4x4(
      &skullRitem->World, XMMatrixScaling(0.4f, 0.4f, 0.4f) *
                              XMMatrixTranslation(0.0f, 1.0f, 0.0f));
  skullRitem->TexTransform = MathHelper::Identity4x4();
  skullRitem->ObjCBIndex = 2;
  skullRitem->Mat = mMaterials["skullMat"].get();
  skullRitem->Geo = mGeometries["skullGeo"].get();
  skullRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  skullRitem->IndexCount = skullRitem->Geo->DrawArgs["skull"].IndexCount;
  skullRitem->StartIndexLocation =
      skullRitem->Geo->DrawArgs["skull"].StartIndexLocation;
  skullRitem->BaseVertexLocation =
      skullRitem->Geo->DrawArgs["skull"].BaseVertexLocation;

  mRitemLayer[(int)RenderLayer::Opaque].push_back(skullRitem.get());
  mAllRitems.push_back(std::move(skullRitem));

  auto gridRitem = std::make_unique<RenderItem>();
  gridRitem->World = MathHelper::Identity4x4();
  XMStoreFloat4x4(&gridRitem->TexTransform, XMMatrixScaling(8.0f, 8.0f, 1.0f));
  gridRitem->ObjCBIndex = 3;
  gridRitem->Mat = mMaterials["tile0"].get();
  gridRitem->Geo = mGeometries["shapeGeo"].get();
  gridRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  gridRitem->IndexCount = gridRitem->Geo->DrawArgs["grid"].IndexCount;
  gridRitem->StartIndexLocation =
      gridRitem->Geo->DrawArgs["grid"].StartIndexLocation;
  gridRitem->BaseVertexLocation =
      gridRitem->Geo->DrawArgs["grid"].BaseVertexLocation;

  mRitemLayer[(int)RenderLayer::Opaque].push_back(gridRitem.get());
  mAllRitems.push_back(std::move(gridRitem));

  XMMATRIX brickTexTransform = XMMatrixScaling(1.5f, 2.0f, 1.0f);
  UINT objCBIndex = 4;
  for (int i = 0; i < 5; ++i) {
    auto leftCylRitem = std::make_unique<RenderItem>();
    auto rightCylRitem = std::make_unique<RenderItem>();
    auto leftSphereRitem = std::make_unique<RenderItem>();
    auto rightSphereRitem = std::make_unique<RenderItem>();

    XMMATRIX leftCylWorld = XMMatrixTranslation(-5.0f, 1.5f, -10.0f + i * 5.0f);
    XMMATRIX rightCylWorld =
        XMMatrixTranslation(+5.0f, 1.5f, -10.0f + i * 5.0f);

    XMMATRIX leftSphereWorld =
        XMMatrixTranslation(-5.0f, 3.5f, -10.0f + i * 5.0f);
    XMMATRIX rightSphereWorld =
        XMMatrixTranslation(+5.0f, 3.5f, -10.0f + i * 5.0f);

    XMStoreFloat4x4(&leftCylRitem->World, rightCylWorld);
    XMStoreFloat4x4(&leftCylRitem->TexTransform, brickTexTransform);
    leftCylRitem->ObjCBIndex = objCBIndex++;
    leftCylRitem->Mat = mMaterials["bricks0"].get();
    leftCylRitem->Geo = mGeometries["shapeGeo"].get();
    leftCylRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
    leftCylRitem->IndexCount =
        leftCylRitem->Geo->DrawArgs["cylinder"].IndexCount;
    leftCylRitem->StartIndexLocation =
        leftCylRitem->Geo->DrawArgs["cylinder"].StartIndexLocation;
    leftCylRitem->BaseVertexLocation =
        leftCylRitem->Geo->DrawArgs["cylinder"].BaseVertexLocation;

    XMStoreFloat4x4(&rightCylRitem->World, leftCylWorld);
    XMStoreFloat4x4(&rightCylRitem->TexTransform, brickTexTransform);
    rightCylRitem->ObjCBIndex = objCBIndex++;
    rightCylRitem->Mat = mMaterials["bricks0"].get();
    rightCylRitem->Geo = mGeometries["shapeGeo"].get();
    rightCylRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
    rightCylRitem->IndexCount =
        rightCylRitem->Geo->DrawArgs["cylinder"].IndexCount;
    rightCylRitem->StartIndexLocation =
        rightCylRitem->Geo->DrawArgs["cylinder"].StartIndexLocation;
    rightCylRitem->BaseVertexLocation =
        rightCylRitem->Geo->DrawArgs["cylinder"].BaseVertexLocation;

    XMStoreFloat4x4(&leftSphereRitem->World, leftSphereWorld);
    leftSphereRitem->TexTransform = MathHelper::Identity4x4();
    leftSphereRitem->ObjCBIndex = objCBIndex++;
    leftSphereRitem->Mat = mMaterials["mirror0"].get();
    leftSphereRitem->Geo = mGeometries["shapeGeo"].get();
    leftSphereRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
    leftSphereRitem->IndexCount =
        leftSphereRitem->Geo->DrawArgs["sphere"].IndexCount;
    leftSphereRitem->StartIndexLocation =
        leftSphereRitem->Geo->DrawArgs["sphere"].StartIndexLocation;
    leftSphereRitem->BaseVertexLocation =
        leftSphereRitem->Geo->DrawArgs["sphere"].BaseVertexLocation;

    XMStoreFloat4x4(&rightSphereRitem->World, rightSphereWorld);
    rightSphereRitem->TexTransform = MathHelper::Identity4x4();
    rightSphereRitem->ObjCBIndex = objCBIndex++;
    rightSphereRitem->Mat = mMaterials["mirror0"].get();
    rightSphereRitem->Geo = mGeometries["shapeGeo"].get();
    rightSphereRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
    rightSphereRitem->IndexCount =
        rightSphereRitem->Geo->DrawArgs["sphere"].IndexCount;
    rightSphereRitem->StartIndexLocation =
        rightSphereRitem->Geo->DrawArgs["sphere"].StartIndexLocation;
    rightSphereRitem->BaseVertexLocation =
        rightSphereRitem->Geo->DrawArgs["sphere"].BaseVertexLocation;

    mRitemLayer[(int)RenderLayer::Opaque].push_back(leftCylRitem.get());
    mRitemLayer[(int)RenderLayer::Opaque].push_back(rightCylRitem.get());
    mRitemLayer[(int)RenderLayer::Opaque].push_back(leftSphereRitem.get());
    mRitemLayer[(int)RenderLayer::Opaque].push_back(rightSphereRitem.get());

    mAllRitems.push_back(std::move(leftCylRitem));
    mAllRitems.push_back(std::move(rightCylRitem));
    mAllRitems.push_back(std::move(leftSphereRitem));
    mAllRitems.push_back(std::move(rightSphereRitem));
  }
}
void DxGraphics::Cube_BuildPSOs() {
  D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;

  //
  // PSO for opaque objects.
  //
  ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  opaquePsoDesc.InputLayout = {mInputLayout.data(), (UINT)mInputLayout.size()};
  opaquePsoDesc.pRootSignature = mRootSignature.Get();
  opaquePsoDesc.VS = {
      reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()),
      mShaders["standardVS"]->GetBufferSize()};
  opaquePsoDesc.PS = {
      reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
      mShaders["opaquePS"]->GetBufferSize()};
  opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  opaquePsoDesc.SampleMask = UINT_MAX;
  opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  opaquePsoDesc.NumRenderTargets = 1;
  opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
  opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  opaquePsoDesc.DSVFormat = mDepthStencilFormat;
  ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(
      &opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));

  //
  // PSO for sky.
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC skyPsoDesc = opaquePsoDesc;

  // The camera is inside the sky sphere, so just turn off culling.
  skyPsoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;

  // Make sure the depth function is LESS_EQUAL and not just LESS.
  // Otherwise, the normalized depth values at z = 1 (NDC) will
  // fail the depth test if the depth buffer was cleared to 1.
  skyPsoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
  skyPsoDesc.pRootSignature = mRootSignature.Get();
  skyPsoDesc.VS = {
      reinterpret_cast<BYTE*>(mShaders["skyVS"]->GetBufferPointer()),
      mShaders["skyVS"]->GetBufferSize()};
  skyPsoDesc.PS = {
      reinterpret_cast<BYTE*>(mShaders["skyPS"]->GetBufferPointer()),
      mShaders["skyPS"]->GetBufferSize()};
  ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(
      &skyPsoDesc, IID_PPV_ARGS(&mPSOs["sky"])));
}
} // namespace ifire